package com.owen.common.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.owen.common.dao.UploadFileDao;
import com.owen.common.domain.UploadFileDO;
import com.owen.common.service.UploadFileService;
import com.owen.common.utils.ShiroUtils;
import com.owen.common.vo.UploadFileVO;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.UUID;

/**
 * 文件上传实现
 *
 * Author： liu
 */
@Service
public class UploadFileServiceImpl implements UploadFileService {

    // 雪花算法id
    private final Snowflake snowflake = IdUtil.createSnowflake(1, 1);

    @Autowired
    private UploadFileDao uploadFileDao;

    @Override
    public UploadFileVO uploadFile(MultipartFile file, String directory) {
        String userId = ShiroUtils.getUserId();
        Assert.isTrue(ObjectUtil.isNotEmpty(userId) , "请登录");
        // 文件大小
        long fileSize = file.getSize();
        Assert.isTrue(ObjectUtil.isNotEmpty(file) && file.getSize() > 0 , "未获取到您要上传的文件信息");
        // 文件名
        String fileName = file.getOriginalFilename();
        Assert.isTrue(ObjectUtil.isNotEmpty(fileName), "文件名获取失败");
        Assert.isTrue(ObjectUtil.isNotEmpty(directory), "未获取到文件路径");
        Path path = Paths.get(directory);
        Assert.isTrue(path.isAbsolute(), "文件将要保存路径非法");
        // 根路径改为文件分割符结尾
        if (!directory.endsWith(File.separator))
            directory = directory.concat(File.separator);
        String todayDay = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN.replace("-", File.separator));
        directory = directory.concat(todayDay).concat(File.separator);
        String fileSuffix = FileNameUtil.getSuffix(fileName);
        UploadFileDO uploadFileDO = new UploadFileDO();
        // 保存文件全路径
        String filePath = directory.concat(UUID.randomUUID().toString());
        // 是否存在文件后缀名
        if (ObjectUtil.isNotEmpty(fileSuffix)) {
            filePath =  filePath.concat(".").concat(fileSuffix);
        }
        InputStream fileIs = null;
        try {
            fileIs = file.getInputStream();
            FileUtil.writeFromStream(fileIs, filePath);
            // 将本次文件上传记录到数据库
            // 雪花算法生成id
            uploadFileDO.setId(snowflake.nextIdStr());
            // 文件名
            uploadFileDO.setFileName(fileName);
            // 文件大小
            uploadFileDO.setFileSize(fileSize);
            uploadFileDO.setPath(filePath);
            // 文件的md5值，用于计算文件是否被修改
            uploadFileDO.setMd5(DigestUtils.md5Hex(FileUtil.readBytes(new File(filePath))));
            // 上传用户的id
            uploadFileDO.setUserId(userId);
            // 创建时间为当前时间
            uploadFileDO.setCreateDate(new Date());
            // 持久化插入到数据库
            uploadFileDao.save(uploadFileDO);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            if (fileIs != null) {
                try {
                    fileIs.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return BeanUtil.toBean(uploadFileDO, UploadFileVO.class);
    }

    @Override
    public UploadFileVO uploadFile(InputStream is, String fileName, String directory) {
        String userId = ShiroUtils.getUserId();
        Assert.isTrue(ObjectUtil.isNotEmpty(userId) , "请登录");
        Assert.isTrue(ObjectUtil.isNotEmpty(fileName), "文件名获取失败");
        Assert.isTrue(ObjectUtil.isNotEmpty(directory), "未获取到文件路径");
        Path path = Paths.get(directory);
        Assert.isTrue(path.isAbsolute(), "文件将要保存路径非法");
        // 根路径改为文件分割符结尾
        if (!directory.endsWith(File.separator))
            directory = directory.concat(File.separator);
        String todayDay = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN.replace("-", File.separator));
        directory = directory.concat(todayDay).concat(File.separator);
        String fileSuffix = FileNameUtil.getSuffix(fileName);
        UploadFileDO uploadFileDO = new UploadFileDO();
        // 保存文件全路径
        String filePath = directory.concat(UUID.randomUUID().toString());
        // 是否存在文件后缀名
        if (ObjectUtil.isNotEmpty(fileSuffix)) {
            filePath =  filePath.concat(".").concat(fileSuffix);
        }
        try {
            FileUtil.writeFromStream(is, filePath);
            // 将本次文件上传记录到数据库
            // 雪花算法生成id
            uploadFileDO.setId(snowflake.nextIdStr());
            // 文件名
            uploadFileDO.setFileName(fileName);
            // 文件大小
            uploadFileDO.setFileSize((long) is.available());
            uploadFileDO.setPath(filePath);
            // 文件的md5值，用于计算文件是否被修改
            uploadFileDO.setMd5(DigestUtils.md5Hex(FileUtil.readBytes(new File(filePath))));
            // 上传用户的id
            uploadFileDO.setUserId(userId);
            // 创建时间为当前时间
            uploadFileDO.setCreateDate(new Date());
            // 持久化插入到数据库
            uploadFileDao.save(uploadFileDO);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return BeanUtil.toBean(uploadFileDO, UploadFileVO.class);
    }

    @Override
    public UploadFileDO findById(String id) {
        return uploadFileDao.findById(id);
    }

    @Override
    public UploadFileDO findByIdAndMd5(String id, String md5) {
        return uploadFileDao.findByIdAndMd5(id, md5);
    }
}
